/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * main.c
 * Copyright (C) Linus Seelinger 2011 <S.Linus@quantentunnel.de>
	 * 
 * chimaira is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
	 * 
 * chimaira is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using GLib;
using Gee;

static bool verbose = false;
public static void verboselog(string log){
	if (verbose)
		stdout.printf (log + "\n");
}



public class Main : Object
{

	[DBus (name = "org.chimaira.server")]
	public class DemoServer : Object {

		public void requestEnvironment (string dbfile){
			verboselog (@"Environment requested >$dbfile<");
			mapEnvironmentHooks[dbfile] = mapEnvironmentHooks[dbfile] + 1;

			if (!(dbfile in mapEnvironments)){
				verboselog (@"Environment loading >$dbfile<");
				mapEnvironments[dbfile] = new environment(dbfile);
				mapEnvironments[dbfile].fileIndex.dataChanged.connect(()=>{//Forward watcher file change signal to dataChanged signal for client
					dataChanged ();
				});
				mapEnvironments[dbfile].fileIndex.importFinished.connect((file, symlink_targets)=>{
					importFinished (dbfile, file, symlink_targets);
				});
			}
		}

		public void releaseEnvironment (string dbfile){
			verboselog (@"Environment released >$dbfile<");
			if (mapEnvironmentHooks[dbfile] > 0)
				mapEnvironmentHooks[dbfile] = mapEnvironmentHooks[dbfile] - 1;
			if (mapEnvironmentHooks[dbfile] == 0){
				verboselog (@"Environment unloading >$dbfile<");
				mapEnvironments.unset (dbfile);
				mapEnvironmentHooks.unset (dbfile);
			}
		}

		private Gee.HashMap<string, environment> mapEnvironments = new Gee.HashMap<string, environment>();
		private Gee.HashMap<string, int> mapEnvironmentHooks = new Gee.HashMap<string, int>();


		
		public signal void dataChanged();
		public signal void importFinished(string dbfile, string file, string[] symlink_targets);

		//=========WATCH DIR MANAGEMENT

		public signal void watchDirsChanged(string[] watchdirs);
		
		public string[] getWatchDirecories(string dbfile){
			environment env = mapEnvironments[dbfile];
			return env.fileIndex.getWatchDirectories ();
		}
		public bool addWatchDirecory(string dbfile, string directory){
			environment env = mapEnvironments[dbfile];
			bool ret = env.fileIndex.addWatchDirectory (directory);
			if (ret)
				watchDirsChanged(env.fileIndex.getWatchDirectories());
			return ret;
		}
		public void removeWatchDirecory(string dbfile, string directory){
			environment env = mapEnvironments[dbfile];
			env.fileIndex.removeWatchDirectory (directory);
			watchDirsChanged(env.fileIndex.getWatchDirectories());
		}

		//=========BACKUP MANAGEMENT

		public int getNumberOfBackups(string dbfile, string dbname){
			environment env = mapEnvironments[dbfile];
			return env.fileIndex.getNumberOfBackups(dbname);
		}
		public string getBackupPath(string dbfile, string dbname, int backupID){
			environment env = mapEnvironments[dbfile];
			return env.fileIndex.getBackupPath(dbname, backupID);
		}
		public void setBackupState(string dbfile, string dbname, bool backup){
			environment env = mapEnvironments[dbfile];
			env.fileIndex.setBackupState(dbname, backup);
		}
		public string getBackupDate(string dbfile, string dbname, int backupID){
			environment env = mapEnvironments[dbfile];
			return env.fileIndex.getBackupDate(dbname, backupID);
		}

		//=========FILE MANAGEMENT
		
		public void import(string dbfile, string path){
			environment env = mapEnvironments[dbfile];
			env.fileIndex.import (File.new_for_path (path));
		}

		
		public string[] proposeProperties(string dbfile, string[] candidates){
			environment env = mapEnvironments[dbfile];
			return env.proposeProperties (candidates);
		}
		public string[] proposeValues(string dbfile, string[] candidates, string property){
			environment env = mapEnvironments[dbfile];
			return env.proposeValues (candidates, property);
		}
		public string[] search(string dbfile, string searchPattern, bool sortByDisplayname){
			environment env = mapEnvironments[dbfile];
			return env.search (searchPattern, sortByDisplayname);
		}
		public string[] refineSearch(string dbfile, string searchPattern, string[] candidates, bool sortByDisplayname){
			environment env = mapEnvironments[dbfile];
			return env.refineSearch (searchPattern, candidates, sortByDisplayname);
		}

		public void removeProperty(string dbfile, string[] dbnames, string property){
			environment env = mapEnvironments[dbfile];
			env.fileIndex.removeProperty (dbnames, property);
			dataChanged ();
		}
		public bool addValue(string dbfile, string[] dbnames, string property, string val){
			environment env = mapEnvironments[dbfile];
			bool ret = env.fileIndex.addValue (dbnames, property, val);
			dataChanged ();
			return ret;
		}
		public void removeValue(string dbfile, string[] dbnames, string property, string val){
			environment env = mapEnvironments[dbfile];
			env.fileIndex.removeValue (dbnames, property, val);
			dataChanged ();
		}
		public stringarray[] getValues(string dbfile, string[] dbnames, string property){
			environment env = mapEnvironments[dbfile];
			stringarray[] array = new stringarray[dbnames.length];
			for (int q = 0; q < dbnames.length; q++){
				array[q].vals = env.fileIndex.getValues (dbnames[q], property);
			}
			return array;
		}
		public string[] getProperties(string dbfile, string dbname){
			environment env = mapEnvironments[dbfile];
			return env.fileIndex.getProperties (dbname);
		}

		public struct stringarray{
			public string[] vals;
		}
		
	}


	static void on_bus_aquired (DBusConnection conn) {
		try {
			var srv = new DemoServer ();
			conn.register_object ("/org/chimaira/server", srv);

			//Request home index db, so all changes to it will be monitored
			srv.requestEnvironment (Environment.get_home_dir () + "/.chimaira/index.sqlite");
		} catch (IOError e) {
			stderr.printf ("Could not register service\n");
		}
	}

	static MainLoop loop;
	static void main (string[] args) {
		if (args.length > 1)
			if (args[1] == "-v")
				verbose = true;
#if DEBUG
		verboselog ("Verbose mode active");
		verboselog ("Register DBus object");
#endif
		Bus.own_name (BusType.SESSION, "org.chimaira.server", BusNameOwnerFlags.NONE,
		              on_bus_aquired,
		              () => {},
		              () => {
						  stderr.printf ("DBus: Could not aquire name\nApparently, chimaira-server is already running! Quit.\n");
						  loop.quit ();
					});
		
		loop = new MainLoop ();
		loop.run ();
	}
}